package com.mystnihon.freeremote.ui.fragment;

import java.util.ArrayList;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import org.json.mine.JSONObject;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import ca.benow.transmission.model.TorrentStatus;
import ca.benow.transmission.model.TorrentStatus.TStatus;
import ca.benow.transmission.model.TransmissionSession.SessionField;

import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.mystnihon.freeremote.FreeRemoteApplication;
import com.mystnihon.freeremote.R;
import com.mystnihon.freeremote.config.Config;
import com.mystnihon.freeremote.db.table.SeedboxTable;
import com.mystnihon.freeremote.manager.TransmissionManager;
import com.mystnihon.freeremote.manager.TransmissionManager.TransmissionResult;
import com.mystnihon.freeremote.manager.TransmissionManager.TransmissionResult.ActionType;
import com.mystnihon.freeremote.manager.TransmissionManager.TransmissionResult.ResultType;
import com.mystnihon.freeremote.ui.TorrentDetailsActivity;
import com.mystnihon.freeremote.ui.UploadActivity;
import com.mystnihon.freeremote.util.FTimer;
import com.mystnihon.freeremote.util.FTimer.FTimerListener;

public class TorrentsListFragment extends SherlockListFragment implements Observer, FTimerListener {

	public static final String ARGS_SEEDBOX = "seedboxs";

	private static final int DEFAULT_REFRESH_TIME = 30;
	private static final String FILE = "file";
	private static final String STATE_TORRENTS = "torrents";
	private static final String TAG = TorrentsListFragment.class.getSimpleName();

	private TransmissionManager mManager;
	private TorrentListAdapter mTorrentListAdapter;

	private ArrayList<TorrentStatus> mTorrents;
	private MenuItem mRefreshActionItem;
	protected ArrayList<Observable> mLstObservable;

	private boolean mForceLocalFileDeletion = false;
	private int mRPCVersionCode = 0;
	private boolean mToggle;
	private FTimer mTimer;
	View vProgress;

	public static TorrentsListFragment newInstance() {
		TorrentsListFragment f = new TorrentsListFragment();
		return f;

	}

	public TorrentsListFragment() {
		mLstObservable = new ArrayList<Observable>();

	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		vProgress = inflater.inflate(R.layout.layout_progress_indeterminate, null);
		return super.onCreateView(inflater, container, savedInstanceState);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);

		setHasOptionsMenu(true);

		initTimer(savedInstanceState);

		initSelectedSeedbox();

		mTorrentListAdapter = new TorrentListAdapter(getSherlockActivity());

		setListAdapter(mTorrentListAdapter);
		setEmptyText(getText(R.string.seedbox_loading));
		getListView().setOnItemLongClickListener(mTorrentListAdapter);
		getListView().setOnItemClickListener(mTorrentListAdapter);

		mLstObservable.add(mManager);

		if (savedInstanceState != null) {
			Object data = savedInstanceState.getSerializable(STATE_TORRENTS);
			if (data != null && data instanceof ArrayList) {
				mTorrents = transform((ArrayList<String>) data);
				mTorrentListAdapter.setTorrents(mTorrents);
			}
		}

	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == UploadActivity.REQUEST_CHOOSE_FILE && resultCode == Activity.RESULT_OK) {
			final Uri uri = (Uri) data.getParcelableExtra(UploadActivity.EXTRA_RESPONSE_URI);
			if (uri != null) {
				AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
				builder.setTitle(R.string.add_torrent_dialog_title)
						.setMessage(getString(R.string.add_torrent_dialog_message, uri.getScheme().equals(TorrentsListFragment.FILE) ? uri.getPath() : uri.toString()))
						.setOnCancelListener(new DialogInterface.OnCancelListener() {

							@Override
							public void onCancel(DialogInterface dialog) {
								dialog.dismiss();

							}
						}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog, int which) {
								dialog.cancel();
							}
						}).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog, int which) {
								mManager.addTorrent(uri);
							}
						}).show();
			}
		}
	}

	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		super.onCreateOptionsMenu(menu, inflater);
		inflater.inflate(R.menu.menu_upload, menu);
		mRefreshActionItem = menu.findItem(R.id.fr_menu_refresh);
	}

	@Override
	public void onDestroy() {
		mManager.stopNetworkOperation();
		super.onDestroy();
	}

	@Override
	public void onHiddenChanged(boolean hidden) {
		super.onHiddenChanged(hidden);
		setMenuVisibility(!hidden);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.fr_menu_refresh:
				refresh();
				break;
			case R.id.fr_menu_upload:
				uploadTorrent();
				break;
			case R.id.fr_menu_resume_all:
				callResumeAll();
				break;
			case R.id.fr_menu_pause_all:
				callPauseAll();
				break;
			case R.id.fr_menu_reannounce:
				callReannounce();
				break;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onPause() {
		mTimer.cleanMessages();
		removeObservers();
		super.onPause();
	}

	@Override
	public void onPrepareOptionsMenu(Menu menu) {
		super.onPrepareOptionsMenu(menu);
		if (mToggle) {
			mRefreshActionItem.setActionView(vProgress);
		} else {
			mRefreshActionItem.setActionView(null);
		}
	}

	@Override
	public void onResume() {
		addObservers();
		mManager.getSession();
		prepareRefresh();
		super.onResume();
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		outState.putSerializable(STATE_TORRENTS, prepareToSerialize(mTorrents));
		mTimer.onSaveInstanceState(outState);
		super.onSaveInstanceState(outState);
	}

	/**
	 * Cause the refresh of the list of torrents.
	 */
	public void refresh() {
		callRefresh();
	}

	@Override
	public void onTick() {
		refresh();

	}

	@SuppressWarnings("unchecked")
	@Override
	public void update(Observable observable, Object data) {

		if (observable instanceof TransmissionManager) {
			TransmissionResult result = (TransmissionResult) data;
			if (result.mAction == ActionType.GetTorrent) {

				toggleActionRefreshIndeterminate(false);
				mTimer.setLastRefreshTime(System.currentTimeMillis());
				mTimer.reset();
			} else if (result.mAction != ActionType.GetSession) {
				mTimer.setLastRefreshTime(System.currentTimeMillis());
				mTimer.setNextRefresh(500);
			}

			if (ResultType.SUCCESS == result.mSuccess) {
				switch (result.mAction) {
					case GetTorrent:

						if (result.mData instanceof ArrayList<?>) {
							mTorrents = (ArrayList<TorrentStatus>) result.mData;
							mTorrentListAdapter.setTorrents(mTorrents);
						}
						break;

					case GetSession:
						if (result.mData instanceof Map) {
							Map<SessionField, Object> map = (Map<SessionField, Object>) result.mData;
							Number versionCode = (Number) map.get(SessionField.rpcVersion);
							mRPCVersionCode = versionCode.intValue();

						}
						break;

					default:
						break;
				}
			} else {
				toggleActionRefreshIndeterminate(false);
				setEmptyText(getText(R.string.seedbox_loading_error));
			}
		}

	}

	protected void addObservers() {
		for (final Observable obs : mLstObservable) {
			obs.addObserver(this);
		}
	}

	protected void removeObservers() {
		for (final Observable obs : mLstObservable) {
			obs.deleteObserver(this);
		}
	}

	private void initSelectedSeedbox() {
		mManager = ((FreeRemoteApplication) getSherlockActivity().getApplication()).getTransmissionManager();
		// if (!mManager.hasInitClient() || mManager.IsClientShouldBeInit()) {
		Object object = getArguments().getParcelable(ARGS_SEEDBOX);
		if (object != null && object instanceof SeedboxTable) {
			if (!mManager.initTransmissionclient((SeedboxTable) object)) {
				// showUpdateSettingsDialog();
			}
			mTimer.cleanMessages();

		}
		// }
	}

	private void initTimer(Bundle savedInstanceState) {
		mTimer = new FTimer();
		mTimer.onRestoreInstanceState(savedInstanceState);
		mTimer.setFTimerListener(this);

	}

	private void callPauseAll() {
		toggleActionRefreshIndeterminate(true);
		mManager.stopTorrentAll();
	}

	private void callRefresh() {
		if (Config.DEBUG_MODE_ENABLED) {
			Log.d(TAG, "Launch refresh");
		}
		if (isAdded()) {
			if (mManager.hasInitClient()) {
				setEmptyText(getText(R.string.seedbox_loading));
				mManager.getTorrentList();
				toggleActionRefreshIndeterminate(true);
			}
		}
	}

	private void callResumeAll() {
		toggleActionRefreshIndeterminate(true);
		mManager.startTorrentAll();
	}

	private void callReannounce() {
		toggleActionRefreshIndeterminate(true);
		mManager.reannounce();
	}

	/**
	 * method to delete a torrent
	 * 
	 * @param torrentId
	 *            the id of the torrent to delete
	 */
	private void deleteTorrent(final int torrentId, final String torrentName) {
		if (mManager.hasInitClient()) {
			AlertDialog.Builder builder = new AlertDialog.Builder(getSherlockActivity());
			LayoutInflater inflater = (LayoutInflater) getSherlockActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			final View v = inflater.inflate(R.layout.layout_dialog_delete, null);
			TextView tv = (TextView) v.findViewById(R.id.diag_title);
			tv.setText(getString(R.string.dialog_delete_torrent, torrentName));
			CheckBox checkbox = (CheckBox) v.findViewById(R.id.diag_checkbox);

			checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

				@Override
				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
					mForceLocalFileDeletion = isChecked;

				}

			});
			builder.setTitle(R.string.dialog_delete_torrent_title).setView(v).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					mManager.removeTorrent(torrentId, mForceLocalFileDeletion);

				}
			}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {

				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();

				}
			}).show().setCancelable(true);
		}
	}

	/**
	 * Will proceed to the launch of the refresh immediately if necessary or
	 * will set a new refresh action at specified time
	 */
	private void prepareRefresh() {
		mTimer.cleanMessages();
		mTimer.setRefreshTime(PreferenceManager.getDefaultSharedPreferences(getSherlockActivity()).getInt(getString(R.string.pref_key_seedbox_refresh_time), DEFAULT_REFRESH_TIME) * 1000L);
		mTimer.initialize();
	}

	/**
	 * Récupère la liste de torrents et la serialize pour la sauvegarder lors
	 * d'un changement d'orientation.
	 */
	private ArrayList<String> prepareToSerialize(ArrayList<TorrentStatus> arrayList) {
		final ArrayList<String> jsonArray = new ArrayList<String>();
		if (arrayList != null)
			for (TorrentStatus string : arrayList) {
				jsonArray.add(string.toString());
			}
		return jsonArray;
	}

	// private void setNextRefresh(long time) {
	// cleanMessages();
	// mHandler.sendEmptyMessageDelayed(MESSAGE_ID, time);
	// }

	/**
	 * Toggle the display of the indeterminate progress state of the refresh
	 * action item.
	 * 
	 * @param toggle
	 *            true to display the indeterminate progress.
	 */
	private void toggleActionRefreshIndeterminate(boolean toggle) {
		mToggle = toggle;
		getSherlockActivity().supportInvalidateOptionsMenu();
	}

	private ArrayList<TorrentStatus> transform(ArrayList<String> fromSerializeJson) {
		final ArrayList<TorrentStatus> tStatusArray = new ArrayList<TorrentStatus>();
		if (fromSerializeJson != null)
			for (String json : fromSerializeJson) {
				tStatusArray.add(new TorrentStatus(new JSONObject(json)));
			}
		return tStatusArray;
	}

	/**
	 * Display the activity to choose a file. You can pass a filter.
	 */
	private void uploadTorrent() {
		if (mManager.hasInitClient()) {
			Intent intent = new Intent(getActivity(), UploadActivity.class);
			intent.putExtra(UploadActivity.EXTRA_NAME_FILTER, ".torrent");
			startActivityForResult(intent, UploadActivity.REQUEST_CHOOSE_FILE);
		}
	}

	/**
	 * @author Utilisateur Niji
	 */
	private final class TorrentActionModes implements ActionMode.Callback {

		public static final int DELETE = Menu.FIRST + 2;
		public static final int PAUSE = Menu.FIRST + 1;
		public static final int PLAY = Menu.FIRST;
		private int mSelectedTorrentId = 0;
		private String mSelectedTorrentName = "";

		public TorrentActionModes(int selectedItem, String name) {
			super();
			mSelectedTorrentId = selectedItem;
			mSelectedTorrentName = name;
		}

		@Override
		public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
			handlerAction(item.getItemId());
			mode.finish();
			return true;
		}

		@Override
		public boolean onCreateActionMode(ActionMode mode, Menu menu) {

			menu.add(0, PLAY, 1, R.string.action_play).setIcon(R.drawable.ic_media_play).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);

			menu.add(0, PAUSE, 2, R.string.action_pause).setIcon(R.drawable.ic_media_pause).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);

			menu.add(0, DELETE, 3, R.string.action_delete).setIcon(R.drawable.content_discard).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);

			return true;
		}

		@Override
		public void onDestroyActionMode(ActionMode mode) {
		}

		@Override
		public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
			return false;
		}

		private void handlerAction(int menuId) {
			switch (menuId) {
				case PLAY:
					if (mManager.hasInitClient()) {
						mManager.startTorrent(mSelectedTorrentId);
					}
					break;
				case PAUSE:
					if (mManager.hasInitClient()) {
						mManager.stopTorrent(mSelectedTorrentId);
					}
					break;
				case DELETE:
					deleteTorrent(mSelectedTorrentId, mSelectedTorrentName);
					break;

				default:
					Toast.makeText(getSherlockActivity(), "Action unknown", Toast.LENGTH_SHORT).show();
					break;
			}
		}
	}

	/**********************************************************************************************************************************
	 * INNER CLASSES
	 **********************************************************************************************************************************/

	private final class TorrentListAdapter extends BaseAdapter implements OnItemClickListener, OnItemLongClickListener {

		private static final int RPC_VERSION_14 = 14;

		private final LayoutInflater mInflater;
		private ArrayList<TorrentStatus> mMyTorrents;

		private final View.OnClickListener mQuickAction = new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				int position = getListView().getPositionForView(v);
				if (position != AdapterView.INVALID_POSITION) {
					TorrentStatus torrentstatus = getItem(position);
					startStop(torrentstatus);
				}
			}
		};

		public TorrentListAdapter(Activity activity) {
			mMyTorrents = new ArrayList<TorrentStatus>();
			mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		@Override
		public int getCount() {
			return mMyTorrents.size();
		}

		@Override
		public TorrentStatus getItem(int position) {
			return mMyTorrents.get(position);
		}

		@Override
		public long getItemId(int position) {
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				holder = new ViewHolder();
				convertView = mInflater.inflate(R.layout.listitem_torrents, parent, false);
				holder.mNameView = (TextView) convertView.findViewById(R.id.listitem_torrent_title);
				holder.mInfoView = (TextView) convertView.findViewById(R.id.listitem_torrent_infos);
				holder.mProgressBar = (ProgressBar) convertView.findViewById(R.id.listitem_torrent_progress);
				holder.mToggleButton = (ImageView) convertView.findViewById(R.id.listitem_torrent_resume_pause);
				holder.mRemainingTime = (TextView) convertView.findViewById(R.id.listitem_torrent_rem_time);

				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			TorrentStatus torrentstatus = getItem(position);
			TStatus status = mRPCVersionCode >= TorrentListAdapter.RPC_VERSION_14 ? torrentstatus.getStatus() : torrentstatus.getOldStatus();
			final double percent = torrentstatus.getPercentDone() * 100;
			final String size = TorrentStatus.humanReadableByteCount(torrentstatus.getSize(), true);
			final String done = TorrentStatus.humanReadableByteCount(torrentstatus.getDownloadedSize(), true);
			final String uploaded = TorrentStatus.humanReadableByteCount(torrentstatus.getUploadedSize(), true);
			final double ratio = torrentstatus.getUploadedRatio();
			final long doneDate = Math.max(0, torrentstatus.getEstimatedTimeLeft());

			holder.mNameView.setText(torrentstatus.getName());
			holder.mProgressBar.setProgress((int) percent);
			holder.mToggleButton.setOnClickListener(mQuickAction);

			if (status == TStatus.Downloading || status == TStatus.Checking || status == TStatus.Seeding || status == TStatus.QueuedDownload || status == TStatus.QueuedSeed) {
				holder.mToggleButton.setImageResource(R.drawable.ic_media_pause);
				holder.mRemainingTime.setText(DateUtils.formatElapsedTime(doneDate));
			} else {
				holder.mToggleButton.setImageResource(R.drawable.ic_media_play);
				holder.mRemainingTime.setText(null);
			}

			if (status == TStatus.Downloading || status == TStatus.QueuedDownload) {
				holder.mInfoView.setText(getString(R.string.seedbox_torrent_download_format, done, size, percent));
			} else if (status == TStatus.Seeding || status == TStatus.QueuedSeed) {
				holder.mInfoView.setText(getString(R.string.seedbox_torrent_upload_format, size, uploaded, ratio));
			} else {
				holder.mInfoView.setText(getString(R.string.seedbox_torrent_pause_format, size, ratio));
			}
			return convertView;
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

			String json = getItem(position).toString();
			if (Config.DEBUG_MODE_ENABLED)
				Log.d(TAG, String.format("JSON : %s", json));
			startActivity(new Intent(getSherlockActivity(), TorrentDetailsActivity.class).putExtra(TorrentDetailsFragment.TORRENT_JSON, json));
		}

		@Override
		public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
			TorrentStatus torrentstatus = getItem(position);
			getSherlockActivity().startActionMode(new TorrentActionModes(torrentstatus.getId(), torrentstatus.getName()));
			return true;
		}

		public void setTorrents(ArrayList<TorrentStatus> torrentss) {
			mMyTorrents = torrentss;
			notifyDataSetChanged();
		}

		private void startStop(TorrentStatus torrentstatus) {
			TStatus status = mRPCVersionCode >= TorrentListAdapter.RPC_VERSION_14 ? torrentstatus.getStatus() : torrentstatus.getOldStatus();
			if (status == TStatus.Downloading || status == TStatus.Checking || status == TStatus.Seeding || status == TStatus.QueuedDownload || status == TStatus.QueuedSeed) {
				if (mManager.hasInitClient()) {
					mManager.stopTorrent(torrentstatus.getId());
				}
			} else {
				if (mManager.hasInitClient()) {
					mManager.startTorrent(torrentstatus.getId());
				}
			}
		}

		class ViewHolder {
			ProgressBar mProgressBar;
			TextView mNameView;
			ImageView mToggleButton;
			TextView mInfoView;
			TextView mRemainingTime;

		}

	}

	// static class WeakHandler extends Handler {
	// WeakReference<TorrentsListFragment> reference;
	//
	// public WeakHandler(TorrentsListFragment fragment) {
	// reference = new WeakReference<TorrentsListFragment>(fragment);
	// }
	//
	// @Override
	// public void handleMessage(Message msg) {
	// if (msg.what == MESSAGE_ID) {
	// Log.d("mLastRefreshTime", "Handle message");
	// reference.get().refresh();
	// }
	// };
	// }

}
